<!--
 * @Author: 孙文豪
 * @Description:
 * @Date: 2022-12-30 15:21:46
 * @LastEditTime: 2023-02-07 13:49:10
 * @LastEditors: 孙文豪
-->
<template>
  <!-- @click.stop="showDown" -->
  <div
    class="swh-drop-down-page"
    @click="showDown"
    :id="parentId"
    ref="dropDownRef"
  >
    <p class="drop-down-text">{{ activeText }}</p>
    <p
      class="iconfont icon-shang drop-down-icon"
      :class="{ show: isShow }"
    ></p>
  </div>
</template>

<script>
import {
  reactive,
  toRefs,
  onMounted,
  onBeforeUnmount,
  ref,
  nextTick,
  watch,
} from "vue";
export default {
  name: "SwhDropDown",
  props: {
    dataList: {
      type: Array,
      default: () => {
        return ["默认值", "选项1", "选项2", "选项3"];
      },
      explain: "下拉菜单数据",
      otherVal: "---",
    },
    defaultValue: {
      type: String,
      default: "默认值",
      explain: "默认选中值",
      otherVal: "---",
    },
    dropDownZindex: {
      type: Number,
      default: 1,
      explain: "下拉框定位层级设置",
      otherVal: "---",
    },
    fixedPosition: {
      type: String,
      default: "---",
      explain: "设置弹窗的上下显示位置，默认根据窗口变化自动切换位置",
      otherVal: "top、bottom",
    },
    transitionSpeed: {
      type: Number,
      default: 0.2,
      explain: "下拉框的过渡速度，单位s",
      otherVal: "0 ~ n",
    },
    getActiveValue: {
      type: Function,
      explain: "获取下拉框选中值",
    },
  },
  setup(props, ctx) {
    const data = reactive({
      activeText: props.defaultValue || props.dataList[0],
      isShow: false,
      dropDownEle: null,
      itemInfo: "",
      times: null,
      dropInfo: null,
      dropEle: null,
      dropTop: "",
      parentId: "", //父级id   自动生成
      sublevelId: "", //子级id
      inDropDownClass: "swh-body-drop-down-box",
      outerLayerBox: null, //外层盒子元素
      outerBoxPd: 10, //外层盒子边距
      inRransitionSpeed:
        props.transitionSpeed < 0 ? 0.2 : props.transitionSpeed, // 校验过渡时间
    });
    // 监听默认值变化
    watch(
      () => props.defaultValue,
      (val) => {
        data.activeText = val;
      }
    );
    const dropDownRef = ref(null); // 获取当前组件中外层元素
    onMounted(() => {
      generateEleId();
    });
    /**
     * 初始化组件唯一标识id，给所有组件按顺序设置不同id
     * 监听相关事件
     */
    const generateEleId = () => {
      nextTick(() => {
        // 获取组件数量
        const ele = document.getElementsByClassName("swh-drop-down-page");
        if (ele.length) {
          for (let i = 0; i < ele.length; i++) {
            // 组件和当前ref获取的组件本身相等就设置id
            if (dropDownRef.value === ele[i]) {
              data.parentId = `swhBodyDrop_${i}`; //设置显示框id
              data.sublevelId = `swhBodyDropSublevel_${i}`; // 设置子级id
            }
          }
        }
        nextTick(() => {
          data.dropEle = document.getElementById(data.parentId); // 根据唯一id获取下拉显示框位置信息
          document.addEventListener("click", activeItem, false); // 监听点击其他区域关闭下拉框
          window.addEventListener("resize", updateDropDown, false); // 监听页面尺寸变化，更改下拉框位置
          document.addEventListener("scroll", updateDropDown, true);
        });
      });
    };
    /**
     * 监听页面滚动时
     * 保持下拉框位置更新
     */
    const updateDropDown = () => {
      if (data.outerLayerBox) {
        data.dropInfo = data.dropEle.getBoundingClientRect(); // 获取下拉显示框位置信息
        updatePosition(); // 更新位置
      }
    };
    // 显示下拉框
    const showDown = () => {
      data.isShow = !data.isShow; //切换下拉框显示隐藏
      if (data.isShow) {
        //显示下拉框  1.清除元素后新建下拉框显示，2.未清除元素改变高度直接显示
        if (!data.outerLayerBox) {
          data.dropInfo = data.dropEle.getBoundingClientRect(); // 获取下拉显示框位置信息
          data.outerLayerBox = document.createElement("div"); //外层包括下拉框元素
          data.dropDownEle = document.createElement("div"); //创建下拉框盒子元素
          data.dropDownEle.setAttribute("class", data.inDropDownClass); //设置id
          data.dropDownEle.setAttribute("id", data.sublevelId); //设置id
          for (let i = 0; i < props.dataList.length; i++) {
            //循环创建下拉每一项
            const listItem = document.createElement("p");
            listItem.setAttribute("class", "swh-list-box-item"); //设置id
            listItem.innerText = props.dataList[i];
            if (listItem.innerText === data.activeText) {
              listItem.className += " active"; // 设置选中类
            }
            if (i === 0) {
              listItem.style.marginTop = "5px";
            } else if (i === props.dataList.length - 1) {
              listItem.style.marginBottom = "5px";
            }
            data.dropDownEle.appendChild(listItem);
          }
          data.outerLayerBox.appendChild(data.dropDownEle);
          document.body.appendChild(data.outerLayerBox);
          data.itemInfo = data.dropDownEle.getBoundingClientRect();
          data.outerLayerBox.addEventListener("click", activeItem, false);
          data.outerLayerBox.style.height = "0px";
          data.outerLayerBox.style.overflow = "hidden"; //动画效果使用
          data.outerLayerBox.style.position = "fixed";
          data.outerLayerBox.style.zIndex = props.dropDownZindex;
          data.dropDownEle.style.width = data.dropInfo.width + "px"; //内容宽度
          data.outerLayerBox.style.width =
            data.dropInfo.width + data.outerBoxPd * 2 + "px"; //外层宽度
          updatePosition();
        } else {
          // 改变下拉框样式显示
          data.outerLayerBox.style.height =
            data.itemInfo.height + data.outerBoxPd * 2 + "px";
          // 获取当前下拉框下的所有子元素，不影响其他下拉框选中样式
          const itemEle =
            data.outerLayerBox.getElementsByClassName("swh-list-box-item");
          for (let i = 0; i < itemEle.length; i++) {
            const Iele = itemEle[i];
            Iele.setAttribute("class", "swh-list-box-item"); //设置类名
            if (Iele.innerText === data.activeText) {
              Iele.className += " active"; // 设置选中类
            }
          }
          clearTimeout(data.times); // 取消元素清除定时
        }
      } else {
        // 清除下拉框
        deleteDropDownEle();
      }
    };
    // 改变下拉框上下显示位置
    const updatePosition = () => {
      if (!data.isShow) return; //有弹窗时才更新位置
      let bool;
      if (props.fixedPosition === "top") {
        //固定向上
        bool = true;
      } else if (props.fixedPosition === "bottom") {
        //固定向下
        bool = false;
      } else {
        //自动切换上下
        bool =
          window.innerHeight - data.itemInfo.height <
          data.dropInfo.top + data.dropInfo.height + 10;
      }
      // 先清除过渡
      data.outerLayerBox.style.transition = "none";
      //改变left
      data.dropDownEle.style.left = data.outerBoxPd + "px";
      data.outerLayerBox.style.left =
        data.dropInfo.left - data.outerBoxPd + "px";
      // 改变上下位置
      if (bool) {
        data.dropDownEle.className = data.inDropDownClass + " bottom-arrow"; // 在上显示
        data.outerLayerBox.style.top = null;
        data.outerLayerBox.style.bottom =
          window.innerHeight - data.dropInfo.top + "px";
      } else {
        data.dropDownEle.className = data.inDropDownClass + " top-arrow"; // 在下显示
        data.outerLayerBox.style.bottom = null;
        data.outerLayerBox.style.top =
          data.dropInfo.top + data.dropInfo.height + "px";
      }
      // 设置高度
      setTimeout(() => {
        data.outerLayerBox.style.transition = `${data.inRransitionSpeed}s`;
        data.outerLayerBox.style.height =
          data.itemInfo.height + data.outerBoxPd * 2 + "px";
      }, 0);
    };
    // 点击每一项选中或其他位置关闭下拉框getAttribute("id")
    const activeItem = (ele) => {
      // 有下拉框显示时
      if (!data.isShow) return;
      const val = ele.target;
      // 获取元素父级class
      const clickEleParentClass =
        val.parentNode && val.parentNode.getAttribute("class");
      // 获取点击项的父元素，下拉框id
      const clickEleParentId =
        val.parentNode && val.parentNode.getAttribute("id");
      /**
       * 1.点击选项，关闭下拉
       * 2.点击下拉箭头关闭其他下拉框，显示当前下拉框
       */
      if (
        clickEleParentClass &&
        clickEleParentClass.includes(data.inDropDownClass)
      ) {
        // id和组件id相等，可执行选中
        if (clickEleParentId !== data.sublevelId) return;
        // true时可以执行
        data.isShow = !data.isShow; // 改变状态
        deleteDropDownEle(); // 清除元素
        if (val.className === "swh-list-box-item") {
          data.activeText = val.innerText; //赋值选中值
          ctx.emit("getActiveValue", data.activeText);
        }
      } else {
        // 这里点击其他下拉框判断id相等就不隐藏，其他展开的隐藏，同时只显示一个下拉框组件
        // sss 这里控制不可同时显示多个下拉框，注释，@click="showDown"  ==> @click.stop="showDown"
        if (clickEleParentId == data.parentId) return;
        data.isShow = !data.isShow; // 改变状态
        deleteDropDownEle(); // 清除元素
      }
    };
    // 清除下拉元素，设置选中值
    const deleteDropDownEle = () => {
      // 先样式清除
      data.outerLayerBox.style.height = "0px";
      // 定时清除元素dom
      data.times = setTimeout(() => {
        // 清除元素
        document.body.removeChild(data.outerLayerBox);
        data.outerLayerBox = null;
      }, data.inRransitionSpeed * 1000 + 100);
    };
    // 组件取消挂载
    onBeforeUnmount(() => {
      // 清除监听页面变化
      window.removeEventListener("resize", updateDropDown, false);
      document.removeEventListener("click", activeItem, false); // 监听点击其他区域关闭下拉框
      document.removeEventListener("scroll", updateDropDown, true);
      if (data.outerLayerBox) {
        // 清除元素
        document.body.removeChild(data.outerLayerBox);
        data.outerLayerBox = null;
      }
    });
    return {
      dropDownRef,
      showDown,
      ...toRefs(data),
    };
  },
};
</script>
<style lang="less">
.swh-body-drop-down-box {
  box-shadow: 0 0px 7px 0px rgba(0, 0, 0, 0.1);
  border: 1px solid @HSE;
  border-radius: 4px;
  caret-color: transparent;
  position: absolute;
  box-sizing: border-box;
  background: #fff;
  &.top-arrow {
    top: 10px;
    &::before {
      content: "";
      position: absolute;
      background: #fff;
      border-top: 1px solid @HSE;
      border-left: 1px solid @HSE;
      width: 7px;
      height: 7px;
      top: -5px;
      left: 50%;
      z-index: 99;
      transform: translateX(-50%) rotate(45deg);
    }
  }
  &.bottom-arrow {
    bottom: 10px;
    &::before {
      content: "";
      position: absolute;
      background: #fff;
      border-bottom: 1px solid @HSE;
      border-right: 1px solid @HSE;
      width: 7px;
      height: 7px;
      bottom: -5px;
      left: 50%;
      transform: translateX(-50%) rotate(45deg);
    }
  }

  .swh-list-box-item {
    line-height: 34px;
    height: 34px;
    text-align: center;
    cursor: pointer;
    color: @HSB;
    font-size: 14px;
    &:hover {
      background: rgb(247, 247, 247);
    }
    &.active {
      color: @TSA;
      background: @TSD;
    }
  }
}
</style>

<style scoped lang="less">
.swh-drop-down-page {
  -moz-user-select: none; /** 火狐*/
  -webkit-user-select: none; /** webkit浏览器*/
  -ms-user-select: none; /** IE10*/
  -khtml-user-select: none; /** 早期浏览器*/
  user-select: none;
  position: relative;
  width: 120px;
  line-height: 30px;
  box-sizing: border-box;
  border: 1px solid rgb(227, 227, 227);
  border-radius: 4px;
  text-align: center;
  font-size: 14px;
  height: 32px;
  cursor: pointer;
  .drop-down-text {
    height: 100%;
    padding: 0 30px 0 10px;
     box-sizing: border-box;
  }
  .drop-down-icon {
    position: absolute;
    right: 0px;
    top: 0;
    height: 30px;
    width: 30px;
    transform: rotate(-180deg);
    font-size: 14px;
    transition: 0.3s;
    color: @HSC;
    &.show {
      transform: rotate(-360deg);
    }
  }
}
</style>
